/******************************************************************************
 * \brief	队列（FIFO、Queue、缓存）的实现
 * \details	不能单独使用，不包含实际的缓存数据，需要和上层结构体结合在一起使用
 * \remarks Linux原生的队列kfifo一次只能操作一个队列，操作变长元素时，判断队列里
 *			元素个数不容易，在复杂场景下使用不方便；消息队列msgbuf的实现又太复杂，
 *			所以在这里自行实现FIFO队列（queue）模块
 * \author	将狼才鲸
 * \date	2023-03-08
 ******************************************************************************/

#ifndef _QUEUE_H_
#define _QUEUE_H_

#include "list.h"
#include <stddef.h>	/* NULL */

#if 0//defined(TARGET_LINUX32) || defined(TARGET_LINUX64)	\
	|| defined(_MSC_VER) || defined(WIN32) || defined(_WIN64)
	/* 如果在操作系统之中，需要上锁 */
#	include <pthread.h>
	typedef pthread_mutex_t queue_lock_t;
#	define queue_lock_init(lock)	pthread_mutex_init((lock), NULL)
#	define queue_lock(lock)			pthread_mutex_lock((lock))
#	define queue_unlock(lock)		pthread_mutex_unlock((lock))
#	define queue_lock_destroy(lock)	pthread_mutex_destroy((lock))
#else	/* OS */
	/* 如果是裸机，无需上锁 */
	typedef int queue_lock_t;
#	define queue_lock_init(lock)
#	define queue_lock(lock)
#	define queue_unlock(lock)
#	define queue_lock_destroy(lock)
#endif	/* OS */

enum {
	QUEUE_USED,	/* 已使用的队列 */
	QUEUE_FREE,	/* 已释放的队列 */
	QUEUE_MEMBER_MAX
};

/* 一个队列的入口 */
typedef struct _queue_entry {
	struct list_head lists[QUEUE_MEMBER_MAX];	/* 队列中的已使用链表和已释放链表 */
	queue_lock_t lock;
} queue_entry_t;

/* 一个队列节点 */
typedef struct _queue {
	struct list_head node;	/* 队列里的一个缓存对应的节点 */
	/* 该节点所属的队列（因为可能会同时存在多个队列，节点也可以跨队列拷贝，
	   所以每个队列元素自身携带队列入口） */
	queue_entry_t *queue_entry;
} queue_t;

/**
 * \brief	初始化队列入口
 */
extern void queue_entry_init(queue_entry_t *pqe);

/**
 * \brief	销毁队列
 * \param	pqe:	queue_entry_t * 队列入口
 */
#define queue_entry_destroy(pqe) queue_lock_destroy((pqe)->lock)

/**
 * \brief	初始化一个队列中的元素
 */
extern void queue_init(queue_t *pq);

/**
 * \brief	将队列元素释放到其它队列或自己队列的已使用入口或已释放入口
 * \param	line:	QUEUE_USED or QUEUE_FREE
 */
extern int queue_put(queue_entry_t *pqe, queue_t *pq, int line);

/**
 * \brief	从队列入口的已使用入口或已释放入口获取一个队列元素
 * \param	line:	QUEUE_USED or QUEUE_FREE
 */
extern queue_t *queue_get(queue_entry_t *pqe, int line);

/**
 * \brief	从队列中申请一个可用的缓存
 * \param	pge:	queue_entry_t * 队列入口指针
 * \return	queue_t *:	获取的队列节点
 */
#define queue_alloc(pqe)	queue_get((pqe), QUEUE_FREE)

/**
 * \brief	用完后将缓存进行释放
 * \param	pg:	queue_t * 一个缓存节点指针
 * \return	错误码
 */
#define queue_free(pq)	queue_put(NULL, (pq), QUEUE_FREE)

/**
 * \brief	预览已使用或者已释放队列中的第一个元素
 * \details	该元素预览后不会被弹出
 * \param	line:	QUEUE_USED or QUEUE_FREE
 */
extern queue_t *queue_peek(queue_entry_t *pqe, int line);

/**
 * \brief	获取已使用或者已释放队列中剩余的元素个数
 * \param	line:	QUEUE_USED or QUEUE_FREE
 */
extern int queue_count(queue_entry_t *pqe, int line);

#endif /* _QUEUE_H_ */
